import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib import font_manager
# 设置中文字体支持
plt.rcParams["font.family"] = ['WenQuanYi Micro Hei', 'Heiti TC', 'SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 2. 检查是否有可用的中文字体
has_chinese_font = False
for font in font_manager.findSystemFonts():
    if any(chinese in font.lower() for chinese in ['heiti', 'simhei', 'wqy', 'noto', 'chinese']):
        has_chinese_font = True
        break

# 如果没有中文字体，使用英文标签
use_chinese_labels = has_chinese_font
# 自定义颜色循环
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b']
plt.rcParams['axes.prop_cycle'] = plt.cycler(color=colors)

def load_data(filename):
    """加载数据文件并返回处理后的数据"""
    try:
        # 读取文件数据
        data = np.loadtxt(filename)
        return data
    except Exception as e:
        print(f"加载文件{filename}失败: {e}")
        return np.array([])

def calculate_metrics(data):
    """计算截止时间到达率指标"""
    if len(data) == 0:
        return 0, 0
    
    # 计算budget（截止要求）：与MATLAB的data_processor.m保持一致
    budget = data[0] / 1000 if len(data) > 0 else 0  # 转换为毫秒
    
    # 计算截止时间到达率（rate）：统计值为1的元素个数
    success_count = np.sum(data == 1) if len(data) > 0 else 0
    rate = success_count / 1000  # 缩放因子
    
    return budget, rate

def generate_plot(topology="abilene"):
    """为指定拓扑生成截止要求与截止时间到达率的关系图"""
    # 定义路由协议
    protocols = ["OSPF", "KSHORT", "DGR", "DDR", "DynamicDDR"]
    
    # 定义实验组数（根据dynamic-ddr.sh中的设置，每组实验有不同的截止要求）
    num_experiments = 50  # 每组拓扑运行50组实验
    
    # 存储所有协议的截止要求和到达率数据
    budget_data = {proto: [] for proto in protocols}
    rate_data = {proto: [] for proto in protocols}
    
    # 遍历协议和实验组数，加载并处理数据
    for i, proto in enumerate(protocols):
        # 转换协议名称为大写（因为文件名使用大写）
        proto_upper = proto.upper()
        
        for exp_id in range(1, num_experiments + 1):
            # 构造文件名（匹配实验数据的实际命名规则）
            filename = os.path.join(
                "/home/lty1207/桌面/ddr/ns-3.38/contrib/ddr/infocomm2024/EXP1/EPOCH1/result",
                topology,
                f"{proto_upper}-{exp_id}.txt"
            )
            
            # 加载数据并计算指标
            data = load_data(filename)
            budget, rate = calculate_metrics(data)
            
            # 只添加有效的数据点
            if budget > 0:
                budget_data[proto].append(budget)
                rate_data[proto].append(rate)
    
    # 创建图形
    plt.figure(figsize=(10, 6))
    
    # 定义线型和标记样式
    styles = [
        ('-', 's'),  # OSPF: 实线+方形标记
        ('-', 'o'),  # KSHORT: 实线+圆形标记
        ('-', '^'),  # DGR: 实线+三角形标记
        ('-', 'd'),  # DDR: 实线+菱形标记
        ('-', 'x'),  # DynamicDDR: 实线+叉形标记
    ]
    
    # 绘制每种协议的曲线
    for i, proto in enumerate(protocols):
        if i < len(styles) and len(budget_data[proto]) > 0:
            linestyle, marker = styles[i]
            plt.plot(
                budget_data[proto],
                rate_data[proto],
                linestyle=linestyle,
                marker=marker,
                label=proto,
                linewidth=2,
                markersize=8
            )
    
    # 设置图形属性
    plt.title(f'{topology.upper()}拓扑下不同路由协议的截止时间到达率')
    plt.xlabel('截止要求 (ms)')
    plt.ylabel('截止时间到达率')
    plt.grid(True, linestyle='--', alpha=0.7)
    plt.axis([0, 50, 0, 1.05])  # 调整坐标轴范围以适应数据
    plt.legend(loc='best')
    
    # 确保保存目录存在
    save_dir = os.path.join(
        "/home/lty1207/桌面/ddr/ns-3.38/contrib/ddr/infocomm2024/EXP1/EPOCH1/result",
        topology
    )
    os.makedirs(save_dir, exist_ok=True)
    
    # 保存图像
    save_path = os.path.join(save_dir, f"{topology}_deadline_achievement_rate.png")
    plt.tight_layout()
    plt.savefig(save_path, dpi=300)
    print(f"图像已保存到: {save_path}")
    
    # 显示图像
    plt.show()

def main():
    # 为每个拓扑生成图像
    topologies = ["abilene","att","cernet","geant"]
    
    # 根据用户要求，可以选择处理所有拓扑或特定拓扑
    for topology in topologies:
        print(f"正在处理{topology}拓扑...")
        generate_plot(topology)
        print(f"{topology}拓扑处理完成。")

if __name__ == "__main__":
    main()